﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

using System.Windows;
using System.Windows.Controls;

namespace All2Iso.Converters
{
    class ModeParameters
    {
        public int Type, HeaderLength, SectorLength, EccLength;

        static public ModeParameters getParams(int type)
        {
            if (type < 0 || type > 2)
                throw new Exception();

            ModeParameters ret = new ModeParameters();
            ret.Type = type;
            ret.SectorLength = 2352;
            if (type == 1)
            {
                ret.HeaderLength = 16;
                ret.EccLength = 288;
            }
            else
            {
                ret.HeaderLength = 24;
                ret.EccLength = 280;
            }

            return ret;
        }
    }

    class BinConverter : IConverter
    {
        byte[] Sync = new byte[12] { 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 };

        MainWindow mw;

        public BinConverter(MainWindow main)
        {
            mw = main;
        }

        private void CheckSig(byte[] data)
        {
            var test = data.Take(12);
            if (!test.SequenceEqual(Sync))
                throw new Exception();
        }

        private int getType(Stream s)
        {
            if (s.Length < 16)
                throw new Exception();

            byte[] sig = new byte[16];
            s.Read(sig, 0, 16);
            CheckSig(sig);

            return sig[15];
        }

        public bool Check(Stream s, int level)
        {
            s.Seek(0, SeekOrigin.Begin);

            int type;
            ModeParameters mParams;
            try
            {
                type = getType(s);
                mParams = ModeParameters.getParams(type);
            }
            catch (Exception)
            {
                return false;
            }

            if (s.Length % mParams.SectorLength != 0)
                return false;
            else if (level <= 1)
                return true;

            s.Seek(0, SeekOrigin.Begin);
            long totSectors = s.Length / mParams.SectorLength;
            mw.SetProgressLimit((int) totSectors);

            try
            {
                for (int i = 0; i < totSectors; i++)
                {
                    CheckSector(s, mParams);
/*                    if (level > 2)
                        CheckEcc(); */
                    mw.UpdateProgress(i);
                }
            }
            catch (Exception)
            {
                mw.ResetProgress();
                return false;
            }

            mw.ResetProgress();
            return true;
        }

        private void CheckSector(Stream s, ModeParameters mParams)
        {
            byte[] data = new byte[24];
            s.Read(data, 0, mParams.HeaderLength);
            CheckSig(data);

            if (data[15] != mParams.Type)
                throw new Exception();

            s.Seek(mParams.SectorLength - mParams.HeaderLength, SeekOrigin.Current);
        }

        public void Convert(Stream input, Stream output)
        {
            input.Seek(0, SeekOrigin.Begin);

            int type = getType(input);
            ModeParameters mParams = ModeParameters.getParams(type);

            if (input.Length % mParams.SectorLength != 0)
                throw new Exception("Wtf");

            input.Seek(0, SeekOrigin.Begin);
            long totSectors = input.Length / mParams.SectorLength;
            mw.SetProgressLimit((int)totSectors);

            byte[] buf = new byte[2048];
            for (int i = 0; i < totSectors; i++)
            {
                input.Seek(mParams.HeaderLength, SeekOrigin.Current);
                input.Read(buf, 0, 2048);
                output.Write(buf, 0, 2048);
                input.Seek(mParams.EccLength, SeekOrigin.Current);

                mw.UpdateProgress(i);
            }

            mw.ResetProgress();
        }
    }
}
